﻿using System.Collections.Generic;
using System.Linq;

using NAudio.Wave;
using NAudio.Wave.SampleProviders;

using iStudio.Structure.Engine;

namespace iStudio.Engine
{
    /// <summary>
    /// NAudio Mixing provider wrapper for iStudio
    /// </summary>
    internal class NAudioMixer : INAudioStream, IOutputProvider
    {
        private readonly MixingSampleProvider _mixProvider;
        private readonly IList<IAudioProvider> _sources;
        private readonly OutputSampleProvider _output;

        public NAudioMixer()
        {
            _output = new OutputSampleProvider();
            _mixProvider = new MixingSampleProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 1));
            _sources = new List<IAudioProvider>();
        }

        public long Position
        {
            get
            {
                return _sources[0].Position;
            }
            set
            {
                if (_sources[0].Position != value)
                {
                    foreach (IAudioProvider stream in _sources)
                    {
                        stream.Position = value;
                    }
                }
            }
        }

        public long Length
        {
            get
            {
                return _sources.Select(stream => stream.Length).Concat(new long[] { 0 }).Max();
            }
        }

        public void AddMixerInput (INAudioStream provider)
        {
            _mixProvider.AddMixerInput(provider);

            _sources.Add(provider);
        }

        public void RemoveMixerInput(INAudioStream provider)
        {
            _mixProvider.RemoveMixerInput(provider);

            _sources.Remove (provider);
        }

        public void RemoveAllMixerInputs ()
        {
            _mixProvider.RemoveAllMixerInputs();

            _sources.Clear();
        }

        public WaveFormat WaveFormat
        {
            get
            {
                return _mixProvider.WaveFormat;
            }
        }
        public int Read(float[] buffer, int offset, int count)
        {
            int readSamples = _mixProvider.Read(buffer, offset, count);

            _output.Process (buffer, offset, readSamples);

            return readSamples;
        }

        #region IOutputProvider

        public OutputSampleProvider Output
        {
            get
            {
                return _output;
            }
        }

        #endregion
    }
}
